/** @file bt_misc.c
  *  
  * @brief This file contains some misc functions like Windows registry
  * process, external firmware image process and debugging function.
  * 
  * (c) Copyright 2003-2007, Marvell International Ltd.
  * All Rights Reserved
  */

#include <windows.h>

#include "bt_dev.h"
#include "bt_def.h"


/********************************************************
        Local Variables
********************************************************/

/********************************************************
        Global Variables
********************************************************/

/********************************************************
        Local Functions
********************************************************/

/********************************************************
        Global Functions
********************************************************/
#ifdef DBG_MSG_TO_RETAILMSG 

#define MSGHEADER	L"[MARVELL-BT]:"

void MrvRETAILMSG(const wchar_t *fmt, ...)
{
  	
    wchar_t dbgbuf[1024] = {MSGHEADER};
    wchar_t  *msgpt = &dbgbuf[wcslen(MSGHEADER)];
    wchar_t* buffer;
	
    va_list ap;
    va_start(ap, fmt);
    buffer = msgpt;
    _vsnwprintf(buffer, sizeof(dbgbuf), fmt, ap);
    va_end(ap);
	
    NKDbgPrintfW (dbgbuf);
	
}
#endif



#ifdef MRVL_PRINT_DBG_MSG  
void MrvPrintFile(const unsigned short *fmt, ...)
{
    va_list     argP; 
    FILE        *MrvDbgfp;
    //DWORD       dwThreadID;
    //DWORD       dwTick;

    if ((MrvDbgfp = fopen("\\My Documents\\DbgMsg.txt","a+")) == NULL)
        return;

    va_start(argP, fmt);
    vfwprintf(MrvDbgfp, fmt, argP);
    fflush(MrvDbgfp);
    va_end(argP);
    fclose(MrvDbgfp);  
}
#endif


#ifdef EXTERNAL_FW_IMAGE     
MRVL_STATUS Fopr_ReadImage(PMRVDRV_ADAPTER Adapter,
                           PUCHAR name,
                           PULONG flen,
                           PUCHAR *addr)
{  
    FILE          *fptr;
    fpos_t        pos;
    ULONG         len,buflen;
    MRVL_STATUS   status;
    PUCHAR        pTempVirtualAddr;

                                  
    if ((fptr = fopen(name, "rb")) == NULL)
    { 
        DBGPRINT(DBG_LOAD|DBG_ERROR,(L"Open Firmware Fail...\n\r"));
        return MRVL_STATUS_FAILURE;
    } 

    if ((status = fseek(fptr, 0, SEEK_END)) != 0)
    {
        DBGPRINT(DBG_LOAD|DBG_ERROR, (L"fseek error\n\r"));   
        return MRVL_STATUS_FAILURE;
    }
   
    if ((status = fgetpos(fptr, &pos)) != 0)
    {
        DBGPRINT(DBG_LOAD|DBG_ERROR, (L"fgetpos error\n\r", pos));
        return MRVL_STATUS_FAILURE;
    }
 
    DBGPRINT(DBG_LOAD|DBG_WARNING, (L"Length of FW:%I64d\n\r", pos)); 
                       
#define EXTRA_PADDING_BUFFER 16

    //add additional 16 bytes for buffer 
    len = (ULONG)pos;
    buflen = len + EXTRA_PADDING_BUFFER;

    // Allocate memory buffer for firmware image
    pTempVirtualAddr = (PUCHAR)SDAllocateMemoryWithTag(buflen, MRVL_MEMORY_TAG);
    if (pTempVirtualAddr == NULL)
    { 
        DBGPRINT(DBG_LOAD|DBG_ERROR, (L"Allocate Firmware BUFFER Fail...\n\r"));
        return MRVL_STATUS_FAILURE;
    }

    *addr = (PUCHAR)pTempVirtualAddr;

    //set position for head of this file   
    pos = 0;
    fsetpos(fptr,&pos);
     
    *flen = fread(pTempVirtualAddr, 1, buflen, fptr);

    if (*flen != len)
    {
        DBGPRINT(DBG_LOAD|DBG_ERROR, (L"Something error in reading FW image file, len. read:%x\n\r", flen));
    }
    
    fclose(fptr);
 
    DBGPRINT(DBG_LOAD|DBG_HELP, (L"Read FW image:%x\n\r", *flen));
    DBGPRINT(DBG_LOAD|DBG_HELP, (L"Allocated VirAddr:%x,%x\n\r",
                                 (ULONG)pTempVirtualAddr, (ULONG)(*addr)));
    
    return MRVL_STATUS_SUCCESS;
}

VOID Fopr_DeallocatedFwImageBuffer(PMRVDRV_ADAPTER Adapter,
                                   ULONG len,
                                   PUCHAR vaddr)
{  
    SDFreeMemory((PVOID)vaddr);
}
#endif //#ifdef EXTERNAL_FW_IMAGE

// Added AddKeyValues() function, which is used to set registry key entries.
// This function was taken from samples in Platform Builder.
/****************************************************************************
 * Function   : AddKeyValues
 *              This function adds the specified key and its value into the
 *              registry under HKEY_LOCAL_MACHINE.
 *
 * Inputs     : LPWSTR KeyName, name of the key to be added to the registry.
 *              PREG_VALUE_DESCR Vals, value associated with this key.
 *
 * Outputs    : None.
 *
 * NOTE       : 1. This function only supports REG_MULTI_SZ strings with 
 *                 one item.
 *              2. Assumes that input Value for the specified Key is NULL
 *                 terminated.
 *
 * Returns    : TRUE  - if successfully added Key & Value
 *              FALSE - if failed to add Key & Value
 ***************************************************************************/
BOOL AddKeyValues(LPWSTR KeyName, PREG_VALUE_DESCR Vals)
{
    DWORD Status;
    DWORD dwDisp;
    HKEY hKey;
    PREG_VALUE_DESCR pValue;
    DWORD ValLen;
    PBYTE pVal;
    DWORD dwVal;
    LPWSTR pStr;

    Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                            KeyName,
                            0,
                            NULL,
                            REG_OPTION_NON_VOLATILE,
                            0,
                            NULL,
                            &hKey,
                            &dwDisp);
    if (Status != ERROR_SUCCESS)
        return (FALSE);

    pValue = Vals;
    while (pValue->val_name)
    {
        switch (pValue->val_type)
        {
            case REG_DWORD:
                pVal = (PBYTE)&dwVal;
                dwVal = (DWORD)pValue->val_data;
                ValLen = sizeof (DWORD);
                break;
            case REG_SZ:
                pVal = (PBYTE)pValue->val_data;
                ValLen = (wcslen ((LPWSTR)pVal) + 1) * sizeof (WCHAR);
                break;
            case REG_MULTI_SZ:
                dwVal = wcslen ((LPWSTR)pValue->val_data);
                ValLen = (dwVal + 2) * sizeof (WCHAR);
                pVal = LocalAlloc (LPTR, ValLen);
                if (pVal == NULL)
                {
                    RegCloseKey (hKey);
                    return (FALSE);
                }
                wcscpy ((LPWSTR)pVal, (LPWSTR)pValue->val_data);
                pStr = (LPWSTR)pVal + dwVal;
                pStr[1] = 0;
                break;
            default:
                ValLen = 0;
                pVal = NULL; 
                return (FALSE);
        } 

        Status = RegSetValueEx(hKey,
                               pValue->val_name,
                               0,
                               pValue->val_type,
                               pVal,
                               ValLen);

        if (pValue->val_type == REG_MULTI_SZ)
            LocalFree(pVal);

        if (Status != ERROR_SUCCESS)
        {
            RegCloseKey (hKey);
            return (FALSE);
        }
        pValue++;
    }

    RegCloseKey (hKey);

    return (TRUE);
}


